/*
 * btn.c
 *
 * Created: 25/01/2013 14:14:14
 *  Author: marionse
 */ 

#include <avr/io.h>
#include <avr/interrupt.h>

#include "board.h"

#include "sysTimer.h"

#include "ModBtn.h"



/************************************************************************/
/* PRIVATE CONSTANT                                                     */
/************************************************************************/

// period de polling des bouton en ms
#define BUTTON_TIMER_PERIOD       10U

// nombre de periode a l'etat stable pour valider le nouveau niveau
// doit etre inferieur a 0xFF
#define BUTTON_DEBOUCE_COUNT       8U

// valeur de validation du compteur de debounce
#define BUTTON_DEBOUNCE_VALID     0xFFU


/************************************************************************/
/* PRIVATE VARIABLES                                                    */
/************************************************************************/

// current status of buttons
static struct SSButtonStatus
{
	// etat valide du bouton
	ButtonState v_state;
	// etat courant du bouton, peut etre different de l'etat valide si le
	// debounce est en cours
	ButtonState c_state;
	// valide le debounce
	Int8U       counter;
} btn_state[NB_BTN_BUTTON];

static TSysTime btn_last_time;

static BtnStatus btn_status; // current logical status of buttons

/************************************************************************/
/* PRIVATE FUNCTIONS                                                    */
/************************************************************************/

/**
* \ brief function to upate buttons status according to state of each button
*/
void btnUpdateStatus( void );

/**
* \brief call periodicly to check button and debounce it.
*
* \return TRUE if valide state of one button has changed
*/
static Boolean btnDebounce( void );


/************************************************************************/
/* ISR FUNCTION                                                         */
/************************************************************************/

ISR(PCINT0_vect)
{
	// user code here
}

ISR(PCINT1_vect)
{
	// user code here
}

ISR(PCINT2_vect)
{
	// user code here
}

ISR(PCINT3_vect)
{
	// user code here
}

/************************************************************************/
/* PUBLIC FUNCTION                                                      */
/************************************************************************/


/**
* \brief initializing function for button management
*
* \return TRUE if success
*/
Boolean modBtnInit( void )
{
	Boolean lo_success = FALSE;
	
	if( NB_BTN_BUTTON <= (8U*sizeof(BtnStatus)) )
	{
		Int8U loop;

		for( loop=0U; loop<NB_BTN_BUTTON; loop++ )
		{
			// configure IO
			*(btnConfig[loop].io_ddr) &= ~(1U << btnConfig[loop].io_bit);
			*(btnConfig[loop].io_port) |= (1U << btnConfig[loop].io_bit);
			
			// read IO to initialize state
			btn_state[loop].c_state = (((*(btnConfig[loop].io_pin))>>btnConfig[loop].io_bit)&0x01U);
			btn_state[loop].v_state = btn_state[loop].c_state;
			
			// initialize counter
			btn_state[loop].counter = BUTTON_DEBOUNCE_VALID;
		}
		
		// start timer
		btn_last_time = sysTimerGetValue();
		
		// compute status
		btnUpdateStatus();

		lo_success = TRUE;
	}
	
	return lo_success;
}

/**
* \brief function call each loop to check if button status has changed
*
* \return current button status
*/
BtnStatus modButtonTick( void )
{
	TSysTime l_time = sysTimerGetValue();
	
	if( ((TSysTime)(l_time-btn_last_time)) > BUTTON_TIMER_PERIOD )
	{
		// call debounce function
		if( TRUE == btnDebounce() )
		{
			// update status
			btnUpdateStatus();
		}
		
		// update time
		btn_last_time -= BUTTON_TIMER_PERIOD;
	}
	
	return btn_status;
}

/************************************************************************/
/* PRIVATE FUNCTIONS                                                    */
/************************************************************************/

/**
* \ brief function to upate buttons status according to state of each button
*/
void btnUpdateStatus( void )
{
	if( NB_BTN_BUTTON <= (8U*sizeof(BtnStatus)) )
	{
		Int8U loop;
		
		// clear status
		btn_status = 0U;

		for( loop=0U; loop<NB_BTN_BUTTON; loop++ )
		{
			btn_status |= (btn_state[loop].v_state<<loop);
		}
	}
}

/**
* \brief call periodicly to check button and debounce it.
*
* \return TRUE if valide state of one button has changed
*/
static Boolean btnDebounce( void )
{
	Boolean lo_state_changed = FALSE;
	Int8U loop;
	Int8U io_level;
	
	// buttons loop
	for ( loop = 0U; loop < NB_BTN_BUTTON; loop++ )
	{
		// read io
		io_level = (((*(btnConfig[loop].io_pin))>>btnConfig[loop].io_bit)&0x01U);
		// check if level has changed
		if( io_level != btn_state[loop].c_state )
		{
			// update state and start debounce
			btn_state[loop].c_state = io_level;
			btn_state[loop].counter = 0U;
		}
		else
		{
			// check if debounce is in progress
			if( BUTTON_DEBOUNCE_VALID != btn_state[loop].counter )
			{
				btn_state[loop].counter += 1U;
				if( BUTTON_DEBOUCE_COUNT < btn_state[loop].counter )
				{
					// ok at min one button has changed
					lo_state_changed = TRUE;
					// validate state
					btn_state[loop].v_state = io_level;
					btn_state[loop].counter = BUTTON_DEBOUNCE_VALID;
				}
			}
		}
	}

	return lo_state_changed;
}
